﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;

namespace SomeKit.Http
{
    public static partial class HttpHelper
    {
        /// <summary>
        /// Creates an instance of an HttpWebRequest object pointing to the resource <paramref name="uri"/>, sets the method to <paramref name="verb"/> 
        /// and finally invokes the <paramref name="headerHandler"/> (if provided).
        /// </summary>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="verb">The method/verb to access the resource.</param>
        /// <param name="headerHandler">The handler to customize the header.</param>
        /// <returns>An instance of an HttpWebRequest, that is prepared according to the provided parameters.</returns>
        public static HttpWebRequest GetRequest(this Uri uri, string verb, 
            Action<HttpWebRequest> headerHandler = null)
        {
            var request = WebRequest.Create(uri) as HttpWebRequest;

            request.Method = verb;
            if (headerHandler != null) 
                headerHandler(request);

            return request;
        }

        /// <summary>
        /// Creates an instance of an HttpWebRequest object pointing to the resource <paramref name="uri"/>, sets the method to <paramref name="verb"/>,
        /// invokes the <paramref name="headerHandler"/> (if provided) and finally sets the content- and accept types.
        /// </summary>
        /// <remarks>
        /// The content- and accept types are set after the invocation of the custom header handler (if provided), so that delegate should not depend on that content- and accept types
        /// are set beforehand. Content and accept types override whatever the custom header handler does (to these headers) unless supplied as null values.
        /// </remarks>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="verb">The method/verb to access the resource.</param>
        /// <param name="contentType">The type of the content in the request. Usually application/xml or application/json.</param>
        /// <param name="acceptType">The type accepted by caller. Usually application/xml or appication/json.</param>
        /// <returns>An instance of an HttpWebRequest, that is prepared according to the provided parameters.</returns>
        /// <param name="headerHandler">The handler to customize the header.</param>
        /// <returns>An instance of an HttpWebRequest, that is prepared according to the provided parameters.</returns>
        public static HttpWebRequest GetRequest(this Uri uri, string verb, string contentType, string acceptType, 
            Action<HttpWebRequest> headerHandler = null)
        {
            return uri.GetRequest(verb, headerHandler.Chain(request =>
            {
                request.SetContentType(contentType);
                request.SetAcceptType(acceptType);
            }));
        }

        /// <summary>
        /// Creates an instance of an HttpWebRequest object pointing to the resource <paramref name="uri"/>, sets the method to <paramref name="verb"/>,
        /// invokes the <paramref name="headerHandler"/> (if provided) and finally sets the content- and accept types to application/xml.
        /// </summary>
        /// <remarks>
        /// The content- and accept types are set after the invocation of the custom header handler (if provided), so that delegate should not depend on that content- and accept types
        /// are set beforehand. Content and accept types override whatever the custom header handler does (to these headers) unless supplied as null values. Also remark that setting of
        /// content-type can be opted out by the <paramref name="setContentType"/> flag; this is due to the fact that setting the content type while using the GET verb will cause an exception.
        /// </remarks>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="verb">The method/verb to access the resource.</param>
        /// <param name="setContentType">Flag telling whether to set the content type. See remarks.</param>
        /// <param name="headerHandler">The handler to customize the header.</param>
        /// <returns>An instance of an HttpWebRequest, that is prepared according to the provided parameters.</returns>
        internal static HttpWebRequest GetXmlRequest(this Uri uri, string verb, bool setContentType = true, Action<HttpWebRequest> headerHandler = null)
        {
            return uri.GetRequest(verb, setContentType ? SerializationType.XML : null, SerializationType.XML, headerHandler);
        }

        /// <summary>
        /// Creates an instance of an HttpWebRequest object pointing to the resource <paramref name="uri"/>, sets the method to <paramref name="verb"/>,
        /// invokes the <paramref name="headerHandler"/> (if provided) and finally sets the content- and accept types to application/json.
        /// </summary>
        /// <remarks>
        /// The content- and accept types are set after the invocation of the custom header handler (if provided), so that delegate should not depend on that content- and accept types
        /// are set beforehand. Content and accept types override whatever the custom header handler does (to these headers) unless supplied as null values. Also remark that setting of
        /// content-type can be opted out by the <paramref name="setContentType"/> flag; this is due to the fact that setting the content type while using the GET verb will cause an exception.
        /// </remarks>
        /// <param name="uri">The resource to be accessed.</param>
        /// <param name="verb">The method/verb to access the resource.</param>
        /// <param name="setContentType">Flag telling whether to set the content type. See remarks.</param>
        /// <param name="headerHandler">The handler to customize the header.</param>
        /// <returns>An instance of an HttpWebRequest, that is prepared according to the provided parameters.</returns>
        internal static HttpWebRequest GetJsonRequest(this Uri uri, string verb, bool setContentType = true, Action<HttpWebRequest> headerHandler = null)
        {
            return uri.GetRequest(verb, setContentType ? SerializationType.JSON : null, SerializationType.JSON, headerHandler);
        }
    }
}
